import os
import sys
import importlib
import json
from collections import namedtuple
from pyminer2.extensions.extensions_manager import log
from pyminer2.pmutil import get_root_dir
import copy

# package.json大概结构
# {
#     "name":...,
#     "display_name":...,
#     "version":...,
#     "description":"...",
#     "icon":"..."
#     "interface":{
#         "file":"",
#         "interface":""
#     },
#     "widgets":[
#         {
#             "file":"",
#             "widget":"",
#             "position":"..."
#             "config":{

#             }
#         }
#     ],
#     "requirements":[
#         {
#             "name":"",
#             "version":""
#         }
#     ]
# }
# 当position为new_tab,config包含:
# name:新选项卡名称
# 当position为tab_选项卡ObjectName,config为空
# 当position为subwindow,config包含:
# name:子窗体名称
# 当position为funcion,config包含:

BASEDIR = get_root_dir()

Info = namedtuple('Info', ['icon', 'name', 'display_name', 'version', 'description', 'path'])

class PublicInterface:
    pass

class ExtensionLoader:
    def load(self, file, ui_inserters):
        self.package = json.load(file)
        self.ui_inserters = ui_inserters
        try:
            self.name = self.package['name']
            self.display_name = self.package['display_name']
            self.version = self.package['version']
            self.description = self.package['description']
            self.icon = self.package['icon']
            self.path = os.path.join(BASEDIR, 'extensions/packages/', self.name)  # 扩展文件夹路径
            main_class = self.load_class(
                {
                    'file': 'main.py',
                    'class_name': 'Extension'
                },
                'class_name'
            )
            
            self.interface = self.load_class(self.package['interface'], 'interface')()
            self.public_interface=self.create_public_interface(self.interface)
            
            for key in getattr(self.interface, 'ui_inserters', []):
                self.ui_inserters[f'extension_{self.name}_{key}'] = self.interface.ui_inserters[key]

            main_class.interface = self.interface
            main_class.public_interface=self.public_interface
            main_class.widgets = []
            for widget in self.package['widgets']:
                widget_class = self.load_widget(widget)
                main_class.widgets.append(widget_class)
            self.main=main_class()
            self.binding_info()
            return self.main
        except KeyError as e:
            log.error('插件的Package.json不完整')
            log.error(e)

    def binding_info(self):
        self.main.info = Info(
            name=self.name,
            icon=self.icon,
            display_name=self.display_name,
            description=self.description,
            version=self.version,
            path=self.path
        )

    def run_code(self, path):
        filepath = os.path.join(self.path, path)
        import_path=os.path.dirname(self.path)      #这里不能直接写self.path,因为所有入口文件都叫main.py,会被Python缓存起来
        sys.path.append(import_path)  # 将模块导入路径设置为扩展文件夹,这样可以直接导入入口文件
        extension_lib_path = os.path.join(BASEDIR, 'extensions/extensionlib')
        sys.path.append(extension_lib_path)

        try:
            model = importlib.import_module(f'{self.name}.{os.path.splitext(os.path.basename(filepath))[0]}')
        except Exception as e:
            log.error(e)
            model = None

        # 删除刚才添加的路径
        for i, p in enumerate(sys.path):
            if p == import_path or path == extension_lib_path:
                del sys.path[i]
        return model

    def load_class(self, obj, class_name):
        if not obj:
            return None
        if not (obj.get('file') and obj.get(class_name)):
            log.error('class_name配置不完整!')
            return
        path = os.path.join(self.path, obj['file'])
        model = self.run_code(path)
        if model:
            if getattr(model, obj[class_name], None):
                return getattr(model, obj[class_name], None)
            else:
                log.error(f"{obj['file']}文件中不存在{obj[class_name]}类")
        else:
            log.error(f"{obj['file']}文件不存在或有误")

    def load_widget(self, widget):
        widget_class = self.load_class(widget, 'widget')
        try:
            if widget.get('auto_insert',True):
                self.ui_inserters[widget['position']].insert(widget_class(), widget['config'])
            return widget_class
        except KeyError as e:
            log.error(f"插件{self.name}的widgets配置不正确!")
            log.error(f"位置:{widget}")

    def create_public_interface(self,interface):
        public_interface=PublicInterface()
        for i in dir(interface):
            if not i.startswith('_'):
                setattr(public_interface,i,getattr(interface,i))
        return public_interface
